home *** CD-ROM | disk | FTP | other *** search
- NAME msscmd
- ; File MSSCMD.ASM
- include mssdef.h
- ; Copyright (C) 1985, 1993, Trustees of Columbia University in the
- ; City of New York. Permission is granted to any individual or institution
- ; to use this software as long as it is not sold for profit. This copyright
- ; notice must be retained. This software may not be included in commercial
- ; products without written permission of Columbia University.
- ;
- ; Edit history:
- ; 27 August 1992 version 3.13
- ; 6 Sept 1991 version 3.11
- ; 13 March 1991 version 3.10
- ; Last edit 21 Oct 1992
- ; 5 Jan 1991 Add \$(Environment variable) substitution.
- ; 9 Sept 1990 Add \v(named variable) substitution.
- ; 21 Nov 1988 Version 2.32
- ; 17 Oct 1988 Make command keyword search failure yield global kstatus of
- ; failure status, to inform Take/Macros of a defective command.
- ; 4 Aug 1988 Fix keyword count initialization in help display.
- ; 1 July 1988 Version 2.31
- ; 7 June 1988 Add comand.impdo flag to permit a keyword search failure to
- ; retry as a DO cmd (macro table). Used only by main Kermit command level.
- ; 27 May 1988 Allow "-<cr>" as line continuation pair and let "\-<cr>"
- ; stand for "-<end of line>". Add comand.cmblen to sense buffer overflow on
- ; calls to cmtxt; if comand.cmblen is left at zero then use 128 byte limit
- ; (comand.cmblen is cleared at command end).
- ; 15 May 1988 Make :label keywords no-ops, make query ordinary char in TAKEs.
- ; 6 May 1988 Show ambiguous keywords at parse time, do graceful interaction.
- ; 28 March 1988 Permit '\%x' (x = '0' or above) in commands as 'variables'
- ; (substituted string of text). Words are obtained from Macro table mcctab.
- ; DEF MAC and DO MAC define variables. DEF macro uses comand.cmper > 0 to
- ; allow '\%x'to be stored as a literal. Variables work in any command except
- ; DEF MAC. Major redesign of whole parser. [jrd]
- ; 4 March 1988 Rewrite keyword parsing to permit non-alphabetized tables
- ; and 8-bit characters. Add byte comand.cmwhite which when non-zero permits
- ; leading whitespace in cmline and cmword commands; it is reset at command
- ; completion. Move procedure Prompt here from mssker. [jrd]
- ; 27 Feb 1988 Add capability of stdin being a file. [jrd]
- ; 1 Jan 1988 version 2.30
-
- public comnd, comand, isdev, iseof, prompt, tolowr, valbuf, valtab
- public parstate, pardone, parfail, nparam, param, lparam, ninter
- public inter, atparse, atpclr, atdispat, cspb, dspb, mprompt, nvaltoa
- public savepoff, saveplen, keyboard, fwrtdir, cspb1
-
- env equ 2CH ; environment address in psp
- braceop equ 7bh ; opening curly brace
- bracecl equ 7dh ; closing curly brace
-
- data segment
- extrn flags:byte, taklev:byte, takadr:word, mcctab:byte
- extrn kstatus:word, oldtak:byte, errlev:byte, psp:word
- extrn portval:word, bdtab:byte, tdfmt:byte, machnam:byte
- extrn verident:word, kstatus:word, errlev:byte, comptab:byte
- extrn termtb:byte, sescur:word, dosnum:word
-
- ; Start Patch structure. Must be first.
- even
- dspb dw code ; segment values for patcher
- dw code1
- dw code2
- dw data
- db 64 dup (0) ; data segment patch buffer
- ; with space for other material, if req'd
- ; end of Patch structure
- progm db 'MS-DOS_KERMIT$' ; for \v(program)
- system db 'MS-DOS$' ; for \v(system)
- keyboard dw 88 ; \v(keyboard) kind of keybd 88/101
-
- comand cmdinfo <>
- cmer00 db cr,lf,'?Program internal error, recovering$'
- cmer01 db cr,lf,'?More parameters are needed$'
- cmer02 db cr,lf,'?Word "$'
- cmer03 db '" is not usable here$'
- cmer04 db '" is ambiguous$'
- cmer07 db cr,lf,'?Ignoring extra characters "$'
- cmer08 db '"$'
- cmer09 db cr,lf,'?Text exceeded available buffer capacity$'
- cmin00 db ' Press ENTER to execute command$'
- cmin01 db ' Use one of the following words in this position:',cr,lf,'$'
- stkmsg db cr,lf,bell,'?Exhausted work space! Circular definition?$'
- crlf db cr,lf,'$'
- ctcmsg db 5eh,'C$'
- cmunk db 'unknown'
- errflag db 0 ; non-zero to suppress cmcfrm errors
- kwstat db 0 ; get-keyword status
- prevch db 0 ; previous char read by cmgetc
- noparse db 0 ; semicolons not special, if non-zero
- subcnt db 0 ; count of chars matched in '\%'
- subtype db 0 ; kind of sub (% or v)
- bracecnt db 0 ; curly brace counter
- cmsflg db 0 ; Non-zero when last char was a space
- cmdbuf db cmdblen dup (0) ; Buffer for command parsing
- even
- cmdstk dw 0 ; stack pointer at comand call time
- cmptab dw 0 ; Address of present keyword table
- cmhlp dw 0 ; Address of present help
- cmwptr dw 0 ; Pointer for next char write
- cmrptr dw 0 ; Pointer for next char read
- cmsiz dw 0 ; Size info of user input
- cmsptr dw 0 ; Place to save a pointer
- mcmprmp dw 0 ; master prompt, string address
- mcmrprs dd 0 ; master prompt, reparse address
- mcmostp dw 0 ; master prompt, stack pointer
- temp dw 0 ; temp (counts char/line so far)
-
- valtab db 1+19 ; table of values for \v(value)
- mkeyw 'argc)',1
- mkeyw 'count)',2
- mkeyw 'date)',3
- mkeyw 'ndate)',14
- mkeyw 'directory)',5
- mkeyw 'dosversion)',19
- mkeyw 'errorlevel)',4
- mkeyw 'keyboard)',10
- mkeyw 'line)',15
- mkeyw 'platform)',8
- mkeyw 'port)',15
- mkeyw 'program)',12
- mkeyw 'session)',17
- mkeyw 'speed)',11
- mkeyw 'status)',13
- mkeyw 'system)',9
- mkeyw 'terminal)',16
- mkeyw 'time)',6
- mkeyw 'ntime)',18
- mkeyw 'version)',7
-
- envtab db 1 ; \$(..) Environment table
- mkeyw 'An Environment variable)',0 ; reserve 0 in valtab
-
- valtmp dw 0
- valbuf db 130 dup (0) ; storage of variable definition
-
- even
- envadr dd 0 ; seg:offset of a string in Environemt
- envlen dw 0 ; length of envadr's string
-
- even ; Control sequence storage area
- maxparam equ 16 ; number of ESC and DCS Parameters
- maxinter equ 16 ; number of ESC and DCS Intermediates
-
- savepoff label word ; Start per session save area
- parstate dw 0 ; parser state, init to startup
- pardone dw 0 ; where to jmp after Final char seen
- parfail dw 0 ; where to jmp if parser fails
- nparam dw 0 ; number of received Parameters
- param dw maxparam dup (0) ; Parameters for ESC
- lparam db 0 ; a single letter Parameter for ESC
- ninter dw 0 ; number of received Intermediates
- inter db maxinter dup (0),0 ; Intermediates for ESC, + guard
- saveplen dw ($-savepoff)
-
- pcmcfrm dd cmcfrm ; FAR pointers to main parser procs
- pcmkeyw dd cmkeyw ; located in code segment code1
- pcmtext dd cmtext
- pcmfil0 dd cmfil0
- pprserr dd prserr
- pcmexit dd cm6
- pfvaltoa dd fvaltoa
- data ends
-
- code1 segment
- cspb1 equ this byte
- db (256-($-cspb1)) dup (0) ; code1 segment patch buffer
- ; end of Patch area
- code1 ends
-
- code segment
- extrn ctlu:near, cmblnk:near, locate:near, takrd:near, dec2di:near
- extrn takclos:near, docom:near, prtasz:near, getenv:near
- extrn getbaud:near, strlen:near, prtscr:near
-
- assume cs:code, ds:data, es:nothing
-
- ; Patch area. Must be first in MSK's Code Seg
- cspb equ this byte
- dw seg code1
- dw seg code2
- dw seg data
- dw seg data1
- db (256-($-cspb)) dup (0) ; code segment patch buffer
- ; end of Patch area
-
- fctlu proc far ; FAR callable versions of items in seg code
- call ctlu ; for calling from code segment code1 below
- ret
- fctlu endp
- fcmblnk proc far
- call cmblnk
- ret
- fcmblnk endp
- fgetbaud proc far
- call getbaud
- ret
- fgetbaud endp
- fgetenv proc far
- call getenv
- ret
- fgetenv endp
- flocate proc far
- call locate
- ret
- flocate endp
- ftakrd proc far
- call takrd
- ret
- ftakrd endp
- fdec2di proc far
- call dec2di
- ret
- fdec2di endp
- fstrlen proc far
- call strlen
- ret
- fstrlen endp
- ftakclos proc far
- call takclos
- ret
- ftakclos endp
- fprtasz proc far
- call prtasz
- ret
- fprtasz endp
- fprtscr proc far
- call prtscr
- ret
- fprtscr endp
- fisdev proc far
- call isdev
- ret
- fisdev endp
- fiseof proc far
- call iseof
- ret
- fiseof endp
- ftolowr proc far
- call tolowr
- ret
- ftolowr endp
- nvaltoa proc near
- call dword ptr pfvaltoa
- ret
- nvaltoa endp
-
- ; This routine parses the specified function in AH. Any additional
- ; information is in DX and BX.
- ; Returns carry clear on success and carry set on failure
-
- COMND PROC NEAR
- mov cmdstk,sp ; save stack ptr for longjmp exit
- mov noparse,0 ; recognize semicolons in Take files
- mov bracecnt,0 ; curly brace counter
- mov al,taklev ; Take level now
- mov oldtak,al ; remember past internal takclos call
- cmp ah,cmeol ; Parse a confirm?
- jne cm2 ; nz = no
- call dword ptr pcmcfrm ; get a Carriage Return end of line
- ret
- cm2: cmp ah,cmkey ; Parse a keyword?
- jne cm3
- call dword ptr pcmkeyw ; try and get one
- ret
- cm3: cmp ah,cmline ; parse line of text
- jne cm4
- call dword ptr pcmtext
- ret
- cm4: cmp ah,cmword ; parse arbitrary word
- jne cm5
- call dword ptr pcmfil0
- ret
- cm5: mov ah,prstr ; else give error
- mov dx,offset cmer00 ; "?Program internal error"
- int dos
- jmp dword ptr pprserr ; reparse
- ; Control-C exit path (far to near)
- cm6: mov sp,cmdstk ; restore command entry stack pointer
- stc
- ret ; and fail immediately (a longjmp)
-
- COMND ENDP
- code ends
-
- code1 segment
- assume cs:code1
-
- ; This routine parses a keyword from the table pointed at by DX, help text
- ; point to by BX. Format of the table is as follows (use macro mkeyw):
- ; addr: db N ; Where N is the # of entries in the table
- ; dw M ; M is the size of the keyword
- ; db 'string' ; String is the keyword
- ; dw value ; Value is data to be returned
- ; Keywords may be in any order and in mixed case.
- ; Return is rskp for success and ret for failure.
-
- ; cmptab: pointer to keyword table (supplied by caller)
- ; cmhlp: pointer to help message (supplied by caller)
- ; cmsptr: pointer to current user word text
- ; cmsiz: length of user text, excluding terminator
- ; comand.cmcr: 0 = empty lines not allowed, 1 = empty lines allowed
- ; comand.cmwhite: non-zero allows leading whitespace for cmline and cmword,
- ; reset automatically at end of call
- ; cmwptr: buffer write pointer to next free byte
- ; cmrptr: buffer read pointer for next free byte
- ; comand.cmper: 0 to do \%x substitution. Set to 0 at end of call
- ; comand.impdo: non-zero permits keyword failure to retry as DO command, reset
- ; automatically at time of failure.
- cmkeyw proc far
- mov cmsiz,0 ; user word length
- mov ax,cmrptr ; get command reading pointer
- mov cmsptr,ax ; set pointer for start of user word
- mov cmhlp,bx ; save the help pointer
- mov cmptab,dx ; save the beginning of keyword table
- mov bx,dx
- cmp byte ptr[bx],0 ; get number of entries in table
- jne cmky1
- jmp cmky7 ; e = no keywords to check, error
- cmky1: mov cmsflg,0ffh ; skip leading spaces/tabs
- call cmgtch ; get char from the user into ah
- jc cmky3 ; c = terminator
- mov dx,cmrptr ; next byte to read
- dec dx ; where we just read a char
- mov cmsptr,dx ; remember start of keyword
- inc cmsiz ; start counting user chars
- cmky2: call cmgtch ; read until terminator
- jc cmky3 ; c = terminator
- inc cmsiz ; count user chars
- jmp short cmky2 ; no terminator yet
-
- cmky3: cmp ah,'?' ; need help?
- jne cmky4 ; ne = no
- jmp cmkyhlp ; do help and exit
- cmky4: cmp ah,escape ; escape?
- jne cmky6 ; ne = no
- call cmkyesc ; process escape
- jc cmky5 ; c = failure (no unique keyword yet)
- mov comand.cmper,0 ; reset to variable recognition
- mov comand.cmkeep,0
- mov comand.impdo,0 ; clear flag to prevent loops
- mov comand.cmquiet,0 ; permit echoing again
- clc
- ret ; return successfully to user
-
- cmky5: cmp cmsiz,0 ; started a word yet?
- je cmky1 ; e = no, ignore escape, keep looking
- jmp cmkyhlp ; ne = yes, show type of error
-
- cmky6: cmp cmsiz,0 ; length of user's text, empty?
- je cmky7 ; e = yes, parse error
- push bx
- mov bx,cmsptr ; point at first user character
- cmp byte ptr[bx],':' ; start of a label?
- pop bx
- jne cmky6a ; ne = no, return success
- mov cmsiz,1 ; say just one byte
- cmky6a: call getkw ; get unique kw, point to it with bx
- jc cmky8 ; c = not found
- add bx,[bx] ; add length of keyword text (CNT)
- add bx,2 ; point at value field
- mov bx,[bx] ; bx = return value following keyword
- xor ax,ax
- mov comand.cmper,al ; reset to variable recognition
- mov comand.cmkeep,al
- mov comand.impdo,al ; clear flag to prevent loops
- mov comand.cmquiet,al ; permit echoing again
- mov errflag,al
- clc
- ret ; return successfully
- ; all other terminators come here
- cmky7: cmp cmsiz,0 ; empty table or empty user's text?
- jne cmky8 ; ne = no
- cmp comand.cmcr,0 ; empty lines allowed?
- jne cmky10 ; ne = yes, do not complain
- push dx
- mov ah,prstr
- mov dx,offset cmer01 ; command word expected
- int dos
- pop dx
- xor al,al
- mov comand.cmquiet,al ; permit echoing again
- mov comand.impdo,al ; clear flag to prevent loops
- stc ; failure
- ret
-
- cmky8: cmp comand.impdo,0 ; failed here, ok to try Macro table?
- je cmky8a ; e = no, use regular exit path
- mov comand.impdo,0 ; yes, but clear flag to prevent loops
- mov cmrptr,offset cmdbuf ; reinit read pointer
- mov comand.cmquiet,1 ; suppress echoing of same keyword
- mov bx,offset docom ; return DO as "found" keyword
- clc
- ret ; return success to invoke DO
-
- cmky8a: mov errflag,1 ; say already doing error recovery
- or kstatus,ksgen ; global command status, failure
- mov comand.cmquiet,0 ; permit echoing again
- call fisdev ; reading pretyped lines?
- jnc cmky9 ; nc = yes, consume rest of line
- cmp taklev,0 ; in a Take file?
- jne cmky9 ; ne = yes
- call cmskw ; display offending keyword
- dec cmrptr ; interactive, backup to terminator
- mov bx,cmrptr ; look at it
- cmp byte ptr [bx],' ' ; got here on space terminator?
- jne cmky10 ; ne = no, (cr,lf,ff) exit failure
- mov ah,prstr ; start a fresh line
- mov dx,offset crlf
- int dos
- call bufreset ; cut back buffer to just before term
- jmp repars ; reparse interactive lines
-
- cmky9: call dword ptr pcmcfrm ; get formal end of command line
- ; to maintain illusion of typeahead
- ; and let user backspace to correct
- ; mistakes (we reparse everything)
- call cmskw ; display offending keyword
- cmky10: mov comand.cmquiet,0 ; permit echoing again
- stc ; say failure
- ret
- cmkeyw endp
-
- ;;;;;; start support routines for keyword parsing.
-
- cmkyesc proc near ; deal with escape terminator
- call bufreset ; reset buffer to end just before ESC
- cmp cmsiz,0 ; user word length, empty?
- jne cmkye2 ; ne = have user text, else complain
- cmkye1: call esceoc ; do normal escape end-of-command
- stc ; say failure to fill out word
- ret
- ; add unique keyword to buffer
- cmkye2: call getkw ; is there a matching keyword?
- jc cmkye1 ; c = ambiguous or not found
- push bx ; unique, bx points to structure
- push si
- mov cx,[bx] ; length of keyword
- add bx,2 ; point to first letter
- mov si,cmwptr ; where next char goes
- mov dx,cmsiz ; length of user word
- add bx,dx ; add chars known so far
- sub cx,dx ; calculate number yet to add
- add cmsiz,cx
- jcxz cmkye4 ; z = none
- mov ah,conout ; display new char
- cmkye3: mov al,[bx] ; get a keyword letter
- inc bx
- call ftolowr ; lowercase
- mov [si],al ; store it
- inc si
- mov dl,al
- int dos ; display it
- loop cmkye3 ; do all new chars
- cmkye4: mov byte ptr[si],' ' ; insert space terminator in buffer
- mov dl,' ' ; display it
- mov ah,conout
- int dos
- inc si
- mov cmrptr,si ; move token pointer after the space
- mov cmwptr,si ; next free slot is after the space
- mov cmsflg,0ffh ; set space-seen flag
- pop si
- pop bx ; bx = keyword structure
- add bx,[bx] ; add length of keyword text
- add bx,2 ; point at value field
- mov bx,[bx] ; bx = return value following keyword
- clc ; carry clear for success
- ret
- cmkyesc endp
-
- esceoc proc near ; do normal escape end-of-command
- push ax
- push dx
- mov ah,conout ; ring the bell
- mov dl,bell
- int dos
- pop dx
- pop ax
- call bufreset ; reset buffer
- stc ; say error condition
- ret
- esceoc endp
-
- ; Help. Question mark entered by user. Display all the keywords that match
- ; user text. If text is null then use external help if available; otherwise,
- ; display all keywords in the table. Removes question mark from buffer and
- ; invokes reparse of command line to-date. User word starts at cmsptr and
- ; is cmsiz bytes long.
- cmkyhlp proc near
- xor cx,cx ; clear number of keyword (none yet)
- cmp cmsiz,0 ; user text given?
- jne cmkyh1 ; ne = yes, use matching keywords
- cmp cmhlp,0 ; external help given?
- jne cmkyh6 ; yes, use it instead of full table
- cmkyh1: mov temp,0 ; count # chars printed on this line
- mov bx,cmptab ; beginning of kw table
- mov ch,[bx] ; length of table
- xor cl,cl ; no keywords or help displayed yet
- inc bx ; point at CNT field
- cmkyh2: cmp cmsiz,0 ; length of user word
- je cmkyh3 ; e = null, use full table
- call cmpwrd ; compare keyword with user word
- jc cmkyh5 ; c = no match, get another keyword
- cmkyh3: mov ax,[bx] ; length of table keyword
- add byte ptr temp,al ; count chars printed so far
- cmp temp,76 ; will this take us beyond column 78?
- jbe cmkyh4 ; be = no, line has more room
- mov byte ptr temp,al ; reset the count
- mov ah,prstr
- mov dx,offset crlf ; break the line
- int dos
- cmkyh4: or cl,cl ; any keywords found yet?
- jnz cmkyh4a ; nz = yes
- mov dx,offset cmin01 ; start with One of the following: msg
- mov ah,prstr
- int dos
- inc cl ; say one keyword has been found
- cmkyh4a:mov dl,spc ; put two spaces before each keyword
- mov ah,conout
- int dos
- int dos
- add temp,2 ; count output chars
- mov di,bx ; get current keyword structure
- add di,2 ; text part
- push cx
- mov cx,[bx] ; string length to cx, offset to di
- call fprtscr ; display counted string
- pop cx
- cmkyh5: dec ch ; are we at end of table?
- jle cmkyh7 ; le = yes, quit now
- add bx,[bx] ; next keyword, add CNT chars to bx
- add bx,4 ; skip CNT and 16 bit value
- jmp cmkyh2 ; go examine this keyword
-
- cmkyh6: mov dx,cmhlp ; external help text
- mov ah,prstr
- int dos
- inc cl ; say gave help already
- cmkyh7: or cl,cl ; found any keywords?
- jnz cmkyh9 ; nz = yes
- mov cx,cmsiz ; length of word
- or cx,cx
- jg cmkyh8 ; g = something to show
- push dx
- mov ah,prstr
- mov dx,offset cmer01 ; command word expected
- int dos
- pop dx
- jmp prserr
- cmkyh8: mov kwstat,0 ; set keyword not-found status
- call cmskw ; display offending keyword
- cmkyh9: mov ah,prstr ; start a fresh line
- mov dx,offset crlf
- int dos
- call bufreset ; cut back buffer to just before '?'
- jmp repars
- cmkyhlp endp
-
- ; See if keyword is ambiguous or not from what the user has typed in.
- ; Return carry set if word is ambiguous or not found, carry clear otherwise.
- ; Uses table pointed at by cmptab, user text pointed at by cmsptr and length
- ; in cmsiz.
- cmambg proc near
- push bx
- push cx
- push dx
- xor dl,dl ; count keyword matches so far
- mov bx,cmptab ; look at start of keyword table
- mov cl,[bx] ; get number of entries in table
- xor ch,ch ; use cx as a counter
- jcxz cmamb8 ; z = no table so always ambiguous
- inc bx ; look at CNT byte of keyword
- cmamb4: call cmpwrd ; user vs table words, same?
- jc cmamb6 ; c = no match
- inc dl ; count this as a match
- cmp dl,1 ; more than one match?
- ja cmamb8 ; a = yes, quit now
- cmamb6: add bx,[bx] ; add CNT chars to bx
- add bx,4 ; skip CNT and 16 bit value
- loop cmamb4 ; do rest of keyword table
- cmp dl,1 ; how many matches were found?
- jne cmamb8 ; ne = none or more than 1: ambiguous
- pop dx ; restore main registers
- pop cx
- pop bx
- clc
- ret ; ret = not ambiguous
- cmamb8: pop dx ; restore main registers
- pop cx
- pop bx
- stc
- ret ; return ambiguous or not found
- cmambg endp
-
- ; Compare user text with keyword, abbreviations are considered a match.
- ; Enter with bx pointing at keyword table CNT field for a keyword.
- ; Return carry clear if they match, set if they do not match. User text
- ; pointed at by cmsptr and length is in cmsiz.
- ; Registers preserved.
-
- cmpwrd proc near
- push cx
- mov cx,cmsiz ; length of user's text
- jcxz cmpwrd2 ; z: null user word matches no keyword
- cmp cx,[bx] ; user's text longer than keyword?
- ja cmpwrd2 ; a = yes, no match
- push ax
- push bx
- push si
- add bx,2 ; point at table's keyword text
- mov si,cmsptr ; buffer ptr to user input
- cld
- cmpwrd1:lodsb ; user text
- mov ah,[bx] ; keyword text
- inc bx ; next keyword letter
- call ftolowr ; force lower case on both chars
- cmp ah,al ; same?
- loope cmpwrd1 ; e = same so far
- pop si
- pop bx
- pop ax
- jne cmpwrd2 ; ne = mismatch
- pop cx ; recover keyword counter
- clc ; they match
- ret
- cmpwrd2:pop cx ; recover keyword counter
- stc ; they do not match
- ret
- cmpwrd endp
-
- ; Get pointer to keyword structure using user text. Uses keyword table
- ; pointed at by cmptab and cmsiz holding length of user's keyword (cmpwrd
- ; needs comand.cmsptr pointing at user's keyword and length of cmsiz).
- ; Structure pointer returned in BX.
- ; Return carry clear for success and carry set for failure. Modifies BX.
- getkw proc near
- push cx
- mov kwstat,0 ; keyword status, set to not-found
- cmp cmsiz,0 ; length of user word, empty?
- je getkw3 ; e = yes, fail
- mov bx,cmptab ; table of keywords
- mov cl,[bx] ; number of keywords in table
- xor ch,ch
- jcxz getkw3 ; z = none, fail
- inc bx ; point to first
- getkw1: call cmpwrd ; compare user vs table words
- jc getkw2 ; c = failed to match word, try next
- mov kwstat,1 ; say found one keyword, maybe more
- push dx
- mov dx,cmsiz ; users word length
- cmp [bx],dx ; same length (end of keyword)?
- pop dx
- je getkw4 ; e = yes, exact match. Done
- call cmambg ; ambiguous?
- jnc getkw4 ; nc = unique, done, return with bx
- mov kwstat,2 ; say more than one such keyword
- getkw2: add bx,[bx] ; next keyword, add CNT chars to bx
- add bx,4 ; skip CNT and 16 bit value
- loop getkw1 ; do all, exhaustion = failure
- getkw3: pop cx
- stc ; return failure
- ret
- getkw4: pop cx
- clc ; return success
- ret
- getkw endp
-
- ; show offending keyword message. Cmsptr points to user word,
- ; cmsiz has length. Modifies AX, CX, and DX.
- cmskw proc near
- cmp comand.cmquiet,0 ; Quiet mode?
- je cmskw0 ; e = no, regular mode
- ret ; else say nothing
- cmskw0: mov ah,prstr ; not one of the above terminators
- mov dx,offset cmer02 ; '?Word "'
- int dos
- mov ah,conout
- mov cx,cmsiz ; length of word
- jcxz cmskw3 ; z = null
- mov ah,conout
- push si
- mov si,cmsptr ; point to word
- cld
- cmskw1: lodsb
- cmp al,' ' ; control code?
- jae cmskw2 ; ae = no
- push ax
- mov dl,5eh ; caret
- int dos
- pop ax
- add al,'A'-1 ; plus ascii bias
- cmskw2: mov dl,al ; display chars in word
- int dos
- loop cmskw1
- pop si
- cmskw3: mov dx,offset cmer03 ; '" not usable here.'
- cmp kwstat,1 ; kywd status from getkw, not found?
- jb cmskw4 ; b = not found, a = ambiguous
- mov dx,offset cmer04 ; '" ambiguous'
- cmskw4: mov ah,prstr
- int dos
- ret
- cmskw endp
- ;;;;;;;;;; end of support routines for keyword parsing.
-
- ; Parse arbitrary text up to a CR. Enter with BX = pointer to output buffer,
- ; DX pointing to help text. Produces asciiz string. Return updated pointer in
- ; BX and output size in AX. Leading spaces are omitted unless comand.cmwhite
- ; is non-zero (cleared upon exit). It does not need to be followed by the
- ; usual call to confirm the line. Byte comand.cmblen can be used to specify
- ; the length of the caller's buffer; cleared to zero by this command to
- ; imply a length of 127 bytes (default) and if zero at startup use 127 bytes.
- cmtext proc far
- mov cmptab,bx ; save pointer to data buffer
- mov cmhlp,dx ; save the help message
- xor cx,cx ; init the char count
- cmp comand.cmblen,0 ; length of user's buffer given?
- jne cmtxt0 ; ne = yes
- mov comand.cmblen,127 ; else set 127 byte limit plus null
- cmtxt0: mov cmsflg,0ffh ; skip initial spaces
- cmp comand.cmwhite,0 ; allow leading whitespace?
- je cmtxt1a ; e = no
- cmtxt1: mov cmsflg,0 ; get all spaces
- cmtxt1a:call cmgtch ; get a char
- jnc cmtxt5 ; nc = non-terminator, put in buffer
- cmp ah,' ' ; space?
- je cmtxt5 ; e = yes, record it
- cmp ah,escape ; escape?
- jne cmtxt2 ; ne = no
- call esceoc ; do normal escape end-of-command
- jmp short cmtxt0 ; try again
-
- cmtxt2: cmp ah,'?' ; asking a question?
- je cmtxt3 ; e = yes
- cmp ah,cr ; formal carriage return?
- je cmtxt2a ; e = yes
- inc cmrptr ; accept char into buffer
- jmp short cmtxt5 ; and record the char
- cmtxt2a:mov bx,cmptab ; return updated pointer
- xor ax,ax
- mov byte ptr[bx],al ; put terminator into the buffer
- mov comand.cmwhite,al ; clear leading whitespace flag
- mov comand.cmper,al ; reset to variable recognition
- mov comand.cmblen,ax ; set user buffer length to unknown
- mov comand.cmkeep,al
- mov ax,cx ; return count in AX
- call rprompt ; restore master prompt level
- clc
- ret
- ; Help processor
- cmtxt3: inc cmrptr ; count the ?
- or cx,cx ; is "?" the first char?
- jnz cmtxt5 ; nz = no, just add to buffer
- dec cmrptr
- mov cmsiz,0 ; no keyword for help
- mov comand.cmwhite,0 ; clear leading whitespace flag
- cmp cmhlp,0 ; external help given?
- jne cmtxt3a ; ne = yes
- mov cmhlp,offset cmin00 ; confirm with c/r msg
- mov comand.cmblen,0 ; set user buf length to unknown
- cmtxt3a:jmp cmkyhlp ; do help process
-
- cmtxt5: inc cx ; increment the count
- mov bx,cmptab ; pointer into destination array
- mov [bx],ah ; put char into the buffer
- inc bx
- xor al,al
- mov [bx],al ; insert null terminator
- mov cmptab,bx
- cmp cx,comand.cmblen ; buffer filled?
- ja cmtxt6 ; a = yes, declare error
- jb cmtxt5a ; a = not filled yet
- mov ah,conout ; notify user that the buffer is full
- mov dl,bell
- int dos
- cmtxt5a:jmp cmtxt1
- cmtxt6: mov ah,prstr
- mov dx,offset cmer09
- int dos
- jmp prserr ; declare parse error
- cmtext endp
-
-
- ; Parse arbitrary text up to whitespace. Enter with DX pointing to output
- ; buffer and BX pointing to help text. Produces asciiz string. Return updated
- ; pointer in DX and input size in AH. Skips leading whitespace unless
- ; comand.cmwhite is non-zero (cleared upon exit). Does a return skip exit.
-
- cmfil0 proc far
- mov cmptab,dx ; save pointer to data buffer
- mov cmhlp,bx ; save the help message
- mov cmsiz,0 ; init the char count
- cmp comand.cmblen,0 ; length of user's buffer given?
- jne cmfil0a ; ne = yes
- mov comand.cmblen,127 ; else set 127 byte limit plus null
- cmfil0a:cmp comand.cmwhite,0 ; allow leading whitespace?
- jne cmfil1 ; ne = yes
- mov cmsflg,0ffh ; omit leading space
- cmfil1: call cmgtch ; get a char
- jc cmfi1a ; c = terminator
- jmp short cmfil5 ; put char into the buffer
- cmfi1a: cmp ah,escape ; escape?
- je cmfi1b ; e = yes
- jmp short cmfil2 ; process other terminators
- cmfi1b: call esceoc ; do normal escape end-of-command
- jmp short cmfil0a ; try again
-
- cmfil2: cmp ah,'?' ; asking a question?
- je cmfil3 ; e = yes
- xchg dx,bx ; re-interchange bx and dx
- xor ax,ax
- mov comand.cmwhite,al ; clear whitespace flag
- mov comand.cmper,al ; reset to variable recognition
- mov comand.cmkeep,al ; do not keep Take file open
- mov comand.cmblen,ax ; set user buffer length to unknown
- mov bx,cmptab ; pointer into destination array
- mov byte ptr[bx],al ; put null terminator into the buffer
- inc bx
- mov ax,cmsiz ; return count in AX
- mov dx,cmptab ; return updated pointer
- xchg dx,bx ; re-interchange bx and dx
- call rprompt ; restore master prompt level
- clc
- ret ; return success
-
- cmfil3: inc cmrptr ; count the ?
- cmp cmsiz,0 ; Is "?" first char?
- jne cmfil5 ; ne = no, just add to buffer
- dec cmrptr
- mov cmsiz,0
- cmp cmhlp,0 ; external help given?
- jne cmfil3a ; ne = yes
- mov cmhlp,offset cmin00 ; confirm with c/r msg
- cmfil3a:jmp cmkyhlp ; do help process
-
- cmfil5: inc cmsiz ; increment the count
- mov bx,cmptab ; pointer into destination array
- mov [bx],ah ; put char into the buffer
- inc bx
- mov cmptab,bx
- mov cx,cmsiz ; length of command so far
- cmp cx,comand.cmblen ; buffer filled?
- ja cmfil7 ; a = yes, declare error
- jb cmfil6 ; a = not filled yet
- mov ah,conout ; notify user that the buffer is full
- mov dl,bell
- int dos
- cmfil6: jmp cmfil1
-
- cmfil7: mov ah,prstr
- mov dx,offset cmer09
- int dos
- jmp prserr ; declare parse error
- cmfil0 endp
-
- ; This routine gets a confirm (CR) and displays any extra non-blank text.
- ; errflag non-zero means suppress "extra text" display in this routine
- ; because another routine is handling errors.
- cmcfrm proc far
- mov comand.cmper,1 ; do not react to \%x substitutions
- cmcfr1: mov cmsflg,0ffh ; set space-seen flag (skip spaces)
- call cmgtch ; get a char
- push cmrptr
- pop temp ; remember first non-space position
- jc cmcfr4 ; c = terminator
- dec temp ; backup to text char
- cmcfr3: mov cmsflg,0ffh ; set space-seen flag (skip spaces)
- call cmgtch
- jnc cmcfr3 ; read until terminator
- cmcfr4: cmp ah,' '
- je cmcfr3 ; ignore ending on space
- cmp ah,escape ; escape?
- jne cmcfr5 ; ne = no
- call esceoc ; do standard end of cmd on escape
- mov ax,cmrptr
- cmp ax,temp ; started text yet?
- je cmcfr1 ; e = no
- jmp short cmcfr3 ; try again
- cmcfr5: cmp ah,'?' ; curious?
- jne cmcfr6 ; ne = no
- mov cmhlp,offset cmin00 ; msg Confirm with c/r
- mov cmsiz,0 ; no keyword
- mov errflag,0
- jmp cmkyhlp ; do help
- cmcfr6: cmp ah,cr ; the confirmation char?
- jne cmcfr3 ; ne = no
- cmp errflag,0 ; already doing one error?
- jne cmcfr7 ; ne = yes, skip this one
- mov cx,cmrptr ; pointer to terminator
- mov dx,temp ; starting place
- sub cx,dx ; end minus starting point = length
- jle cmcfr7 ; le = nothing to display
- push dx ; save source pointer
- mov ah,prstr
- mov dx,offset cmer07 ; ?Ignoring extras
- int dos
- pop dx
- mov bx,1 ; stdout handle, cx=count, dx=src ptr
- mov ah,write2 ; allow embedded dollar signs
- int dos
- mov ah,prstr
- mov dx,offset cmer08 ; trailer msg
- int dos
- cmcfr7: mov errflag,0
- mov comand.cmper,0 ; reset to variable recognition
- mov comand.cmkeep,0
- call rprompt ; restore master prompt level
- clc ; return confirmed
- ret
- cmcfrm endp
-
- ;;; Routines to get and edit incoming text.
-
- ; Detect '\%x' (x = '0' or above) and substitute the matching Macro string
- ; in place of the '\%x' phrase in the user's buffer. If comand.cmper != 0
- ; then treat '\%' as literal characters. If no matching parameter exists
- ; just remove '\%x'. Ditto for \v(variable). Returns carry clear if nothing
- ; done, else carry set and new text already placed in user's buffer.
- ; Includes \v(variable) and \$(Environment variable) and \m(macro name).
- ; Uses depth-first recursion algorithm. All registers preserved.
- subst proc near
- cmp comand.cmper,0 ; recognize '\%','\v(','\$(','\m(' ?
- jne subst2 ; ne = no, treat as literals
- cmp ah,'\' ; is it the first char of the pattern?
- jne subst1 ; ne = no, try next
- mov subcnt,1 ; say first is matched
- mov subtype,0
- jmp short subst2 ; exit successfully
- subst1: cmp subcnt,1 ; first char matched already?
- ja subst3 ; a = first two have been matched
- jb subst2 ; b = none yet
- inc subcnt ; assume a match follows
- mov subtype,ah ; remember kind of substitution
- or subtype,20h ; convert to lower case
- cmp ah,'%' ; second match char, same?
- je subst2 ; e = yes
- cmp subtype,'v' ; \v(...)?
- je subst2 ; e = yes
- cmp subtype,'$' ; \$(..)?
- je subst2
- cmp subtype,'m' ; \m(..)?
- je subst2
- subst1a:mov subcnt,0 ; mismatch, clear match counter
- mov subtype,0 ; clear substitution kind
- subst2: clc ; carry clear = no substitution done
- ret
- subst3: cmp subtype,'v' ; doing \v(..)?
- je subst3a ; e = yes
- cmp subtype,'$' ; doing \$(..)?
- je subst3a ; e = yes
- cmp subtype,'m' ; doing \m(..)?
- jne subst3b ; ne = no, do \%<char>
- subst3a:cmp ah,'(' ; have leading parenthesis?
- jne subst1a ; ne = no, mismatch, exit
- jmp subst10 ; process \v(..), \$(..), \m(..)
- subst3b:mov subcnt,0 ; do \%<char>, clear match counter
- cmp ah,'0' ; third char is '0' or above?
- jb subst1a ; b = out of range, no match
- push bx ; save working regs
- push cx
- push es
- sub cmrptr,3 ; reread commands where backslash was
- call bufreset ; reset buffer to this point
- push cmptab ; save current keyword parsing parms
- push cmsptr
- push cmsiz
- mov bx,cmrptr ; points at backslash
- mov cmsptr,bx ; direct keyword routine to it
- mov cmsiz,3 ; three bytes (\%x) of user text
- mov cmptab,offset mcctab ; use Macro table for new text
- call getkw ; get ptr, bx, to matching keyword
- pop cmsiz ; restore borrowed keyword parameters
- pop cmsptr
- pop cmptab
- jc substx ; c = not found, keep after pops
- cmp taklev,maxtak ; room in take level?
- jae subst6 ; ae = no
- mov cx,[bx] ; length of found word
- add cx,2 ; plus count field
- add bx,cx ; point to 16 bit value (string ptr)
- mov es,[bx] ; point to string structure segment
- xor bx,bx
- mov cx,es:[bx] ; length of string
- add takadr,size takinfo ; pointer to new Take structure
- inc taklev
- mov bx,takadr ; pointer to new Take structure
- mov [bx].takbuf,es ; segment of Take buffer
- mov [bx].takcnt,cx ; number of unread bytes
- mov [bx].taktyp,0fdh ; flag as an internal macro
- mov [bx].takptr,2 ; init pointer to definition itself
- substx: pop es
- pop cx
- pop bx
- stc ; set carry to say have stored chars
- ret
-
- subst6: mov ah,prstr
- mov dx,offset stkmsg ; out of work space msg
- int dos
- jmp prserr ; and declare parse error
-
- ; \m(..), \v(..), \$(..)
- subst10:push bx ; save working regs
- push cx
- push es
- push cmptab ; save current keyword parsing parms
- push cmsptr
- push cmsiz
- push cmhlp
- push dx
- mov subcnt,0 ; clear match counter
- mov cmhlp,0
- mov ax,cmrptr
- mov valtmp,ax ; remember current read pointer
- mov cmsptr,ax ; start of word
- mov cmptab,offset valtab ; table of keywords for \v(..)
- cmp subtype,'v' ; \v(..)?
- je subst10a ; e = yes
- mov cmptab,offset envtab ; Environment variable table \$(..)
- cmp subtype,'$' ; \$(..)?
- je subst10a ; e = yes
- mov cmptab,offset mcctab ; main Macro table for \m(..)
- subst10a:mov cmsflg,0 ; see leading spaces/tabs
- mov cmsiz,0 ; word size
- subst11:call cmgtch ; read a character into ah
- jnc subst13 ; nc = non-terminator
- cmp ah,'?' ; need help?
- jne subst11a ; ne = no
- jmp cmkyhlp ; do help and exit
- subst11a:cmp ah,escape ; escape?
- jne subst12 ; ne = no
- mov bx,cmsptr ; where word started
- mov cmrptr,bx ; omit word to date
- mov cmwptr,bx
- call cmkyesc ; process escape
- mov dx,1 ; signal valtoa to add trailing space
- jnc subst14 ; nc = success (found the keyword)
- ;
- subst12:mov bx,cmsptr ; where word started
- sub bx,3 ; back over "\v(" pr "\$(" part
- mov cmrptr,bx ; omit "\v(..." or "\$(..." to date
- mov cmwptr,bx ; and "\m(..." too
- jmp repars ; reparse command without \v(...
- ;
- subst13:inc cmsiz ; count user chars
- cmp ah,')' ; end bracket?
- jne subst11 ; ne = no, keep looking
- dec cmsiz ; omit user's ')' from tests
- cmp subtype,'$' ; \$(..)?
- je subst13a ; e = yes, no keyword in table
- call getkw ; \m(..) and \v(..) test for keyword
- jc subst12 ; c = failure
- jmp short subst13b ; success
-
- subst13a:call envvar ; search Environment for the word
- jc subst12 ; c = failure
- mov bx,offset envtab+1 ; Environment data structure
-
- subst13b:mov ax,valtmp ; where word started
- mov cmrptr,ax
- sub ax,3 ; backup to "\v(" or "\$("
- mov cmrptr,ax ; write output where backslash was
- mov cmwptr,ax
- mov cx,[bx] ; bx = structure pointer, cx=keyw len
- add cx,2 ; skip count byte
- add bx,cx ; point at 16 bit value field
- mov bx,[bx] ; get value to bx for valtoa
- xor dx,dx ; signal valtoa to not add trailing sp
- subst14:
- cmp taklev,maxtak ; room in take level?
- jb subst15 ; b = yes
- mov dx,offset stkmsg ; out of work space msg
- mov ah,prstr ; display error message
- int dos
- jmp short subst17
- subst15:push di
- call valtoa ; make text be an internal macro
- jc subst16 ; c = failed
- add takadr,size takinfo ; pointer to new Take structure
- inc taklev ; next Take level
- push bx
- mov bx,takadr ; address of take structure
- mov ax,ds
- mov [bx].takbuf,ax ; segment of Take buffer
- mov [bx].takptr,offset valbuf+2 ; offset of beginning of def text
- mov [bx].takcnt,di ; # of chars in buffer
- mov [bx].taktyp,0fdh ; flag as an internal macro
- pop bx
- subst16:pop di
- subst17:pop dx
- pop cmhlp
- pop cmsiz ; restore borrowed keyword parameters
- pop cmsptr
- pop cmptab
- jmp repars ; reparse cmd line with new material
- subst endp
-
- ; Make an internal macro defined as the text for one of the value variables.
- ; Use incoming DX as trailing space suppression flag, if null.
- valtoa proc near
- push dx ; save trailing space flag
- mov di,offset valbuf+2 ; start text here
- mov word ptr [di],0 ; fill buffer with sweet nothings
- ; BX has index of variable
- cmp bx,0 ; Environment?
- jne valtoa1 ; ne = no
- mov cx,envlen ; string length
- jcxz valtoa0 ; z = empty
- push es
- push ds
- mov ax,ds
- mov es,ax ; destination is es:di
- lds si,envadr ; ds:si is source from Environment
- cld
- rep movsb ; copy string
- pop ds ; recover ds
- pop es
- valtoa0:jmp valtoa30
-
- valtoa1:cmp bx,1 ; ARGC?
- jne valtoa2 ; ne = no
- call wrtargc ; write argc
- jmp valtoa30
- valtoa2:cmp bx,2 ; COUNT?
- jne valtoa3 ; ne = no
- call wrtcnt ; write it
- jmp valtoa30
- valtoa3:cmp bx,3 ; DATE?
- jne valtoa4
- call wrtdate
- jmp valtoa30
- valtoa4:cmp bx,4 ; ERRORLEVEL?
- jne valtoa5 ; ne = no
- call wrterr
- jmp valtoa30
- valtoa5:cmp bx,5 ; DIR?
- jne valtoa6
- call wrtdir
- jmp valtoa30
- valtoa6:cmp bx,6 ; TIME?
- jne valtoa7
- call wrttime
- jmp valtoa30
- valtoa7:cmp bx,7 ; VERSION?
- jne valtoa8 ; ne = no
- mov ax,version ; get version such as 300
- call fdec2di ; convert binary to asciiz
- mov word ptr [di],0020h ; space, null
- inc di
- jmp valtoa30
- valtoa8:cmp bx,8 ; PLATFORM?
- jne valtoa9 ; ne = no
- call wrtplat ; get machine name, e.g. "IBM-PC"
- jmp valtoa30
- valtoa9:cmp bx,9 ; SYSTEM?
- jne valtoa10 ; ne = no
- call wrtsystem ; get "MS-DOS" string
- jmp valtoa30
- valtoa10:cmp bx,10 ; KEYBOARD?
- jne valtoa11 ; ne = no
- call wrtkbd ; 88 or 101 value
- jmp valtoa30
- valtoa11:cmp bx,11 ; SPEED?
- jne valtoa12 ; ne = no
- push di
- call fgetbaud ; read baud rate from hardware
- pop di
- mov bx,portval
- mov ax,[bx].baud
- cmp al,byte ptr bdtab ; index versus number of table entries
- jb valtoa11a ; b = index is in the table
- mov si,offset cmunk-2 ; unrecognized value, say "unknown"
- mov bx,7 ; length of string
- jmp short valtoa11c
- valtoa11a:mov si,offset bdtab ; ascii rate table
- mov cl,[si] ; number of entries
- inc si ; point to an entry
- valtoa11b:
- mov bx,[si] ; length of text string
- cmp ax,[si+bx+2] ; our index vs table entry index
- je valtoa11c ; e = match
- add si,bx ; skip text
- add si,4 ; skip count and index word
- loop valtoa11b ; look again
- mov si,offset cmunk-2 ; unrecognized value, say "unknown"
- mov bx,7 ; length of string
- valtoa11c:mov cx,bx ; length of string
- add si,2 ; point at string
- rep movsb ; copy string
- jmp valtoa30
-
- valtoa12:cmp bx,12 ; PROGRAM?
- jne valtoa13 ; ne = no
- call wrtprog ; get "MS-DOS_KERMIT" string
- jmp valtoa30
- valtoa13:cmp bx,13 ; STATUS?
- jne valtoa14 ; ne = no
- call wrtstat ; compose status string
- jmp valtoa30
- valtoa14:cmp bx,14 ; NDATE?
- jne valtoa15 ; ne = no
- call wrtndate
- jmp valtoa30
- valtoa15:cmp bx,15 ; LINE, PORT?
- jne valtoa16 ; ne = no
- call wrtport
- jmp valtoa30
- valtoa16:cmp bx,16 ; TERMINAL?
- jne valtoa17 ; ne = no
- call wrtterm
- jmp valtoa30
- valtoa17:cmp bx,17 ; SESSION (internal Telnet)?
- jne valtoa18 ; ne = no
- mov ax,sescur ; get internal Telnet session ident
- inc ax ; count from 1 for users (0 == none)
- call fdec2di ; convert binary to asciiz
- mov word ptr [di],0020h ; space, null
- inc di
- jmp valtoa30
- valtoa18:cmp bx,18 ; \v(ntime) (seconds in day)?
- jne valtoa19 ; ne = no
- mov ah,gettim ; get DOS time of day
- int dos ; ch=hh, cl=mm, dh=ss, dl=0.01 sec
- mov bx,60
- mov al,ch ; hours
- mul bl ; to minutes
- xor ch,ch
- add ax,cx ; plus minutes
- mov cl,dh ; preserve seconds
- mul bx ; need carry out to DX
- add ax,cx ; add seconds
- adc dx,0
- mov cx,10 ; down to 16 bit size
- div cx
- call fdec2di ; convert binary to asciiz
- xchg ax,dx
- call fdec2di ; convert binary to asciiz
- mov word ptr [di],0020h ; space, null
- inc di
- jmp short valtoa30
- valtoa19:cmp bx,19 ; \v(dosversion)?
- jne valtoa29 ; ne = no
- mov ax,dosnum ; DOS verson, major high, minor low
- push ax
- xchg ah,al
- xor ah,ah
- call fdec2di ; write major
- pop ax
- xor ah,ah
- cmp al,10 ; less than 10?
- ja valtoa19a ; a = no
- mov byte ptr [di],'0' ; use two digits for minor
- inc di
- valtoa19a:call fdec2di ; write minor
- mov word ptr [di],0020h ; space, null
- inc di
- jmp short valtoa30
- valtoa29:pop dx ; assume an internal Macro
- add takadr,size takinfo ; pointer to new Take structure
- inc taklev ; next Take level
- push bx
- mov ax,bx ; save seg of string here
- mov bx,takadr ; address of take structure
- mov [bx].takbuf,ax ; segment of Take buffer
- mov [bx].takptr,2 ; offset of beginning of def text
- push es
- mov es,ax ; segment of string definition
- mov di,es:[0] ; get length of string text (count)
- pop es
- mov [bx].takcnt,di ; # of chars in buffer
- mov [bx].taktyp,0fdh ; flag as an internal macro
- pop bx
- jmp short valtoax ; exit early with CARRY SET(!)
-
- valtoa30:pop dx ; trailing space flag
- or dx,dx ; leave the spaces?
- jnz valtoa31 ; nz = yes
- cmp word ptr [di-1],0020h ; trailing space?
- jne valtoa31 ; ne = no
- dec di ; remove space
- valtoa31:sub di,offset valbuf+2 ; di = length of the buffer contents
- clc
- ret
- valtoax:stc
- ret
- valtoa endp
-
- ; Far callable version
- fvaltoa proc far
- call valtoa
- ret
- fvaltoa endp
- ; Set envadr to the string following the <variable=> keyword in the
- ; Environment and set envlen to its length after removing leading and
- ; trailing whitespace.
- ; <variable> starts at ds:<valtmp>, of length cmsiz-1, and can be mixed case.
- ; Return carry set if can't find the <variable=> line in the Environment.
- envvar proc near
- push es
- mov bx,valtmp ; start of variable name
- mov cx,cmsiz ; length of variable name, w/o ')'
- or cx,cx ; empty?
- jle envvar3 ; le = nothing to look for, fail
- push bx
- push cx
- envvar1:mov al,byte ptr [bx] ; scan variable name in our buffer
- cmp al,'a' ; lower case
- jb envvar2 ; b = no
- cmp al,'z' ; still in lower case range?
- ja envvar2 ; a = no
- and al,not 20h ; convert to DOS's upper case
- mov byte ptr [bx],al ; replace char
- envvar2:inc bx
- loop envvar1
- pop cx
- pop bx ; find "<variable>=" in Environment
- call fgetenv ; dx = offset in Environment of "="
- jnc envvar4 ; nc = success
- envvar3:pop es ; no such variable
- stc ; c = failure
- ret
- ; dx has offset in Environment of char "="
- ; ds:valtmp is start of variable name, cmsiz is length + 1 of the name.
- ; Return seg:offset and length variables so we can copy from there in valtoa
- envvar4:push di
- push si
- xor ax,ax
- mov word ptr envadr,ax ; offset in env of variable's string
- mov word ptr envadr+2,ax ; seg of same
- mov envlen,ax ; length of string
- mov es,psp ; our Prog Seg Prefix segment
- mov ax,es:word ptr[env] ; pick up Environment address
- mov es,ax ; set es: to Environment segment
- mov di,dx ; line scan pointer
- cmp byte ptr es:[di],'=' ; did we stop on this?
- jne envvar5 ; ne = no
- inc di ; skip the "=" char
- envvar5:mov al,es:[di] ; scan over leading white space
- inc di
- or al,al ; end of line terminator?
- jz envvarf ; z = yes, fail
- cmp al,TAB ; HT?
- jne envvar6 ; ne = no
- mov al,' ' ; HT becomes a space
- envvar6:cmp al,' ' ; white space?
- je envvar5 ; scan off white space
- dec di ; backup to non-white char
- mov word ptr envadr,di ; offset of string in Environment
- mov word ptr envadr+2,es ; seg of string in Environment
- mov si,di ; remember starting offset here
- ; remove trailing spaces from string
- xor al,al ; a null
- mov cx,127 ; max length to search
- cld
- repne scasb ; skip over non-nulls
- dec di ; backup to null
- dec di ; backup to last string char
- mov cx,di ; ending offset
- inc cx ; count the char
- sub cx,si ; minus starting offset yields length
- jcxz envvar9 ; z = empty string
- envvar7:mov al,es:[di] ; last char
- dec di ; backup one char
- cmp al,' ' ; space?
- je envvar8 ; e = yes
- cmp al,TAB ; HT?
- jne envvar9 ; ne = no, end of white space
- envvar8:loop envvar7 ; keep looking
- envvar9:mov envlen,cx ; store the length
- clc ; say success
- jmp short envvarx
- envvarf:stc ; say failure
- envvarx:pop si
- pop di
- pop es
- ret
- envvar endp
-
- ; Read chars from Take file, keyboard, or redirected stdin. Edit and remove
- ; BS & DEL, Tab becomes space, act on Control-C, pass Control-U and Control-W.
- ; Do echoing unless comand.cmquiet is non-zero. Do semicolon comments in Take
- ; and indirect stdin files (\; means literal semicolon). Return char in AL.
- CMGETC proc near ; Basic raw character reader
- cmget01:cmp prevch,0 ; left over char yet to be exported?
- je cmget02 ; e = no
- mov al,prevch ; get old char
- mov prevch,0 ; clear storage
- jmp cmget6 ; analyze it
- cmget02:cmp taklev,0 ; in a Take file?
- jne cmget1 ; ne = yes, do Take reader section
- call fisdev ; is stdin a device or a file?
- jnc cmget20 ; nc = file (redirection of stdin)
- jmp cmget10 ; c = device, do separately
-
- cmget20:call fiseof ; see if file is empty
- jc cmget21 ; c = EOF on disk file
- mov ah,coninq ; read the char from file, not device
- int dos
- cmp al,cr ; is it a cr?
- je cmget01 ; yes, ignore and read next char
- cmp al,ctlz ; Control-Z?
- je cmget21 ; e = yes, same as EOF here
- cmp al,lf ; LF's end lines from disk files
- jne cmget8 ; ne = not LF, pass along as is
- mov al,cr ; make LF a CR for this parser
- call fiseof ; see if this is the last char in file
- jnc cmget8 ; nc = not EOF, process new CR
- cmget21:mov flags.extflg,1 ; EOF on disk file, set exit flag
- jmp short cmget6 ; do echoing and return
-
- cmget1: push bx ; read from Take file
- mov bx,takadr ; offset of this Take structure
- cmp [bx].takcnt,0 ; bytes remaining in Take buffer
- jne cmget4 ; ne = not empty
- cmp [bx].taktyp,0feh ; type of Take (file?)
- jne cmget3 ; ne = no (macro)
- call ftakrd ; read another buffer
- cmp [bx].takcnt,0 ; anything in the buffer?
- jne cmget4 ; ne = yes
- cmget3: pop bx ; clear stack
- jmp short cmget5 ; close take file
-
- cmget4: push si
- push es
- mov es,[bx].takbuf ; segment of Take buffer
- mov si,[bx].takptr ; current offset in Take buffer
- mov al,es:[si] ; read a char from Take buffer
- inc si
- mov [bx].takptr,si ; move buffer pointer
- dec [bx].takcnt ; decrease number of bytes remaining
- pop es
- pop si
- pop bx
- cmp al,ctlz ; Control-Z?
- jne cmget6 ; ne = no
- cmget5: push bx
- mov bx,takadr ; offset of this Take structure
- mov ah,[bx].taktyp ; save kind of Take/macro
- pop bx
- cmp ah,0fdh ; internal macro?
- je cmget5b ; e = yes, close but no auto-CR
- cmp comand.cmkeep,0 ; keep Take/macro open after eof?
- jne cmget5a ; ne = yes
- cmget5b:push ax
- call ftakclos ; close take file
- pop ax
- cmp ah,0fdh ; internal macro?
- jne cmget5a ; ne = no, file or regular macro
- jmp cmgetc ; internal macros have no auto CR
- cmget5a:mov al,cr ; report cr as last char
- mov noparse,0 ; and say end of comment
- ; start common code
- cmget6:
- cmp al,lf ; line feed?
- jne cmget8 ; ne = no
- jmp cmget01 ; yes, ignore and read another char
- ; handle comments (echo but not parse)
- cmget8: cmp noparse,0 ; parsing?
- jne cmget9 ; ne = yes, do echo and no parse
- cmp prevch,0 ; have previous char to analyze?
- jne cmget8c ; ne = yes
- cmp taklev,0 ; in a Take file or Macro?
- je cmget8e ; e = no, use ";" as a literal
- push bx ; treat ";" as literal in int macros
- mov bx,takadr ; offset of this Take structure
- cmp [bx].taktyp,0fdh ; internal macro?
- pop bx
- je cmget8e ; e = yes, semicolons are literals
- cmp al,'\' ; start of '\;'?
- jne cmget8a ; ne = no
- mov prevch,al ; yes, maybe. save '\' til later
- jmp cmget02 ; read next char
- cmget8a:cmp al,';' ; possible start of comment?
- jne cmget8e ; no, export al
- mov al,' ' ; replace ';' with space for comment
- jmp short cmget9 ; go start a comment
-
- cmget8c:cmp al,';' ; end of '\;'?
- je cmget8d ; e = yes, omit leading backslash
- xchg prevch,al ; no, save new, recover old '\'
- jmp short cmget8e ; export '\'
- cmget8d:mov prevch,0 ; clear old '\'
- cmget8e:jmp short cmget12 ; do parsing
-
- ; echo comment
- cmget9: cmp flags.takflg,0 ; echoing take files?
- je cmget9a ; e = no
- push ax
- push dx
- mov ah,conout ; echo current char
- mov dl,al
- int dos
- pop dx
- pop ax
- cmget9a:mov noparse,0 ; cr ends comment
- cmp al,cr ; end of comment?
- je cmget13 ; e = yes, export cr
- mov noparse,1 ; still in comment
- jmp cmget01 ; read more chars
-
- ; read from tty device
- cmget10:mov ah,coninq ; Get a char from device, not file
- int dos ; with no echoing
- or al,al
- jnz cmget12 ; ignore null bytes of special keys
- int dos ; read and discard scan code byte
- jmp short cmget10 ; try again
-
- cmget12:cmp al,'C'and 1Fh ; Control-C?
- je cmget14 ; e = yes
- cmp al,TAB ; tab is replaced by space
- jne cmget13 ; ne = not tab
- mov al,' '
- ret
- cmget13:cmp al,LF ; LF becomes CR interactively
- jne cmget13a
- mov al,CR
- cmget13a:ret ; normal exit, char is in AL
-
- cmget14:mov ah,prstr ; Control-C handler
- push dx
- mov dx,offset ctcmsg ; show Control-C
- int dos
- pop dx
- mov prevch,0
- mov flags.cxzflg,'C' ; tell others the news
- jmp dword ptr pcmexit ; fail immediately via longjmp
- cmgetc endp
-
- ; Read chars from user (cmgetc). Detect terminators. Reads from buffer
- ; cmbuf. Set read pointer cmrptr to next free buffer byte if
- ; char is not a terminator: chars CR, LF, FF, '?' (returns carry set for
- ; terminators). Do ^U, ^W editing, convert FF to CR plus clear screen.
- ; Edit "-<cr>" as line continuation, "\-<cr>" as "-<end of line>".
- ; Return char in AH.
- CMINBF proc near ; Buffer reader, final editor
- cmp cmwptr,offset cmdbuf+size cmdbuf-3 ; max buffer size - 3
- jb cminb1 ; b = not full for writing
- mov ah,conout ; almost full, notify user
- push dx
- mov dl,bell
- int dos
- pop dx
- cmp cmrptr,offset cmdbuf+size cmdbuf ; reading beyond buffer?
- jb cminb1 ; b = no
- mov ah,prstr
- mov dx,offset cmer09 ; command too long
- int dos
- jmp prserr ; overflow = parse error
-
- cminb1: push bx
- mov bx,cmrptr ; read pointer
- mov ah,[bx] ; get current command char while here
- cmp bx,cmwptr ; do we need to read more?
- pop bx ; no if cmrptr < cmwptr
- jb cminb2 ; b: cmrptr < cmwptr (have extra here)
- call cmgetc ; no readahead, read another into al
- mov ah,al ; keep char in 'ah'
- push bx
- mov bx,cmwptr ; get the pointer into the buffer
- mov [bx],ah ; put it in the buffer
- inc bx
- mov cmwptr,bx ; inc write pointer
- pop bx
- jmp short cminb1 ; call cmgetc until cmwptr >= cmrptr
- ; Char to be delivered is in ah
- cminb2: cmp ah,'W' and 1fh ; is it a ^W?
- jne cminb3
- call cntrlw ; kill the previous word
- jnc cminbf ; nc = no change, get another char
- jmp repars ; need a new command scan (cleans stk)
-
- cminb3: cmp ah,'U' and 1fh ; is it a ^U?
- jne cminb3a ; ne = no
- mov cmwptr,offset cmdbuf ; reset buffer write pointer
- jmp repars ; go start over (cleans stack)
- ; BS and DEL
- cminb3a:cmp ah,DEL ; delete code?
- je cminb3b ; e = yes
- cmp ah,BS ; Backspace (a delete operator)?
- jne cminb4 ; ne = no
- cminb3b:call bufdel ; delete char from buffer
- jc cminb3c ; c = did erasure
- jmp cminbf ; no erasure, ignore BS, get more
- cminb3c:jmp repars ; could have deleted previous token
-
- cminb4: push bx ; look for hyphen or \hyphen
- cmp ah,cr ; check for hyphen line continuation
- jne cminb4b ; ne = not end of line
- mov bx,cmwptr ; get the pointer into the buffer
- cmp bx,offset cmdbuf-2 ; do we have a previous char?
- jb cminb4b ; b = no
- cmp byte ptr[bx-2],'-' ; previous char was a hyphen?
- jne cminb4b ; ne = no
- pop bx
- call bufdel ; delete the hyphen
- jmp repars
- cminb4b:pop bx
- ; Echoing done here
- cmp comand.cmquiet,0 ; quiet mode?
- jne cminb5 ; yes, skip echoing
- cmp taklev,0 ; in a take file?
- je cminb4a ; e = no
- cmp flags.takflg,0 ; echo take file?
- je cminb5 ; e = no
- cminb4a:push ax ; save the char
- cmp ah,' ' ; printable?
- jae cminb4c ; yes, no translation needed
- cmp ah,cr ; this is printable
- je cminb4c
- cmp ah,lf
- je cminb4c
- cmp ah,escape ; escape?
- je cminb4d ; do not echo this character
- push ax ; show controls as caret char
- push dx
- mov dl,5eh ; caret
- mov ah,conout
- int dos
- pop dx
- pop ax
- add ah,'A'-1 ; make control code printable
- cminb4c:push dx
- mov dl,ah
- mov ah,conout
- int dos ; echo it ourselves
- pop dx
- cminb4d:pop ax ; and return char in ah
-
- cminb5: cmp ah,cr ; carriage return?
- je cminb6
- cmp ah,lf ; line feed?
- je cminb6
- cmp ah,ff ; formfeed?
- jne cminb7 ; none of the above, report bare char
- call fcmblnk ; FF: clear the screen and
- push bx
- push cx
- push dx
- call flocate ; Home the cursor
- mov bx,cmwptr ; make the FF parse like a cr
- mov byte ptr [bx-1],cr ; pretend a carriage return were typed
- pop dx
- pop cx
- pop bx
- cminb6: cmp cmwptr,offset cmdbuf ; parsed any chars yet?
- jne cminb7 ; ne = yes
- cmp comand.cmcr,0 ; bare cr's allowed?
- jne cminb7 ; ne = yes
- jmp prserr ; If not, just start over
- cminb7: clc
- ret
- cminbf endp
-
- ; Read chars from cminbf. Cmrptr points to next char to be read.
- ; Compresses repeated spaces if cmsflg is non-zero. Exit with cmrptr pointing
- ; at a terminator or otherwise at next free slot.
- ; Non-space then space acts as a terminator but cmrptr is incremented.
- ; Substitution variables, '\%x', are detected and expanded. Return char in AH.
-
- CMGTCH proc near ; return char in AH, from rescan buf
- call cminbf ; get char from buffer or user
- push bx
- mov bx,cmrptr ; get read pointer into the buffer
- mov ah,[bx] ; read the next char
- inc bx
- mov cmrptr,bx ; where to read next time
- pop bx
- call subst ; examine for text substitution
- jnc cmgtc1 ; nc = no substitutions done
- jmp repars ; reparse line with new material
-
- cmgtc1: cmp ah,' ' ; space?
- jne cmgtc3 ; ne = no
- cmp bracecnt,0 ; are we within braces?
- jne cmgtc3 ; ne = yes, treat space as literal
- cmp cmsflg,0 ; space flag, was last char a space?
- jne cmgtch ; ne = yes, get another char
- mov cmsflg,0FFH ; Set the space(s)-seen flag
- mov ah,' ' ; character for caller
- stc ; set carry for terminator
- ret ; return space as a terminator
- cmgtc3: mov cmsflg,0 ; clear the space-seen flag
- cmp ah,braceop ; opening brace?
- jne cmgtc3b ; ne = no
- inc bracecnt ; count it
- jmp short cmgtc3c
- cmgtc3b:cmp ah,bracecl ; closing brace?
- jne cmgtc3c ; ne = no
- sub bracecnt,1 ; count down and get a sign bit
- jns cmgtc3c ; ns = no underflow
- mov bracecnt,0 ; catch underflows
- cmgtc3c:cmp ah,escape ; terminators remain in buffer but
- je cmgtc4 ; are ready to be overwritten
- cmp ah,'?' ; is the user curious?
- jne cmgtc3a ; ne = no
- cmp taklev,0 ; in a Take file?
- jne cmgtc3d ; ne = yes, make query ordinary char
- je cmgtc4
- cmgtc3a:cmp ah,cr
- je cmgtc4
- cmp ah,lf
- je cmgtc4
- cmp ah,ff
- je cmgtc4
- cmgtc3d:clc ; carry clear for non-terminator
- ret
- cmgtc4: dec cmrptr ; point at terminating char
- stc ; set carry to say it is a terminator
- ret
- cmgtch endp
-
- ; Reset comand.cmdbuf write pointer (cmwptr) to where the read pointer
- ; (cmrptr) is now. Discards material not yet read.
- bufreset proc near
- push cmrptr ; where next visible char is read
- push ax ; count removed curly braces
- push si
- mov si,cmrptr ; where to look
- mov cx,cmwptr ; last place being removed
- sub cx,si ; length to examine
- cld
- bufres1:lodsb
- cmp al,braceop ; opening brace, counted already?
- jne bufres2 ; ne = no
- dec bracecnt ; uncount it
- jmp short bufres3
- bufres2:cmp al,bracecl ; closing brace, counted already?
- jne bufres3 ; jne = no
- inc bracecnt ; uncount it
- bufres3:loop bufres1
- cmp bracecnt,0 ; negative?
- jge bufres4 ; ge = no
- mov bracecnt,0
- bufres4:pop si
- pop ax
- pop cmwptr ; where new char goes in buffer
- ret
- bufreset endp
-
- ; Delete character from screen and adjust buffer. Returns carry clear if
- ; no erasure, carry set otherwise.
- bufdel proc near
- push ax
- push si
- mov si,cmrptr
- mov al,[si]
- cmp al,braceop ; opening brace, counted already?
- jne bufdel1 ; ne = no
- dec bracecnt ; uncount it
- jmp short bufdel2
- bufdel1:cmp al,bracecl ; closing brace?
- jne bufdel2 ; ne = no
- inc bracecnt ; uncount it
- bufdel2:cmp bracecnt,0 ; negative?
- jge bufdel3 ; ge = no
- mov bracecnt,0
- bufdel3:pop si
- pop ax
- dec cmrptr ; remove previous char from buffer
- cmp cmrptr,offset cmdbuf ; back too far?
- jae bufde2 ; ae = no, material can be erased
- mov cmrptr,offset cmdbuf ; set to start of buffer
- call bufreset ; reset buffer
- mov bracecnt,0 ; ensure this is now cleared
- clc ; say no erasure
- ret
- bufde2: call bufreset ; reset buffer
- stc ; say did erasure
- ret
- bufdel endp
-
- ; Come here is user types ^W when during input. Remove word from buffer.
- cntrlw proc near
- push ax
- push cx
- push dx
- call bufreset ; truncate buffer at cmrptr
- mov cx,cmrptr ; read pointer
- sub cx,offset cmdbuf ; compute chars in buffer
- clc ; say have not yet modified line
- jcxz ctlw2 ; z = nothing to do, exit no-carry
- push es
- std ; scan backward
- mov ax,ds
- mov es,ax ; point to the data are
- mov di,cmwptr ; looking from here
- dec di
- mov al,' '
- repe scasb ; look for non-space
- je ctlw1 ; all spaces, nothing to do
- inc di ; move back to non-space
- inc cx
- repne scasb ; look for a space
- jne ctlw1 ; no space, leave ptrs alone
- inc di
- inc cx ; skip back over space
- ctlw1: inc di
- pop es
- cld ; reset direction flag
- mov cmwptr,di ; update pointer
- stc ; set carry to say modified line
- ctlw2: pop dx
- pop cx
- pop ax
- ret
- cntrlw endp
-
- ; Jump to REPARS to do a rescan of the existing buffer.
- ; Jump to PRSERR on a parsing error (quits command, clears old read material)
-
- PRSERR PROC NEAR
- mov cmwptr,offset cmdbuf ; initialize write pointer
- mov ah,prstr
- mov dx,offset crlf ; leave old line, start a new one
- int dos
- call rprompt ; restore master prompt level
- ; reparse current line
- REPARS: mov cmrptr,offset cmdbuf ; reinit read pointer
- mov comand.cmper,0 ; reset to variable recognition
- mov cmsflg,0ffh ; strip leading spaces
- mov subcnt,0 ; clear substitution state variables
- mov subtype,0
- mov bracecnt,0
- cmp taklev,0 ; in Take cmd?
- je prser2 ; e = no
- cmp flags.takflg,0 ; echo contents of Take file?
- je prser3 ; e = no
- prser2: call fctlu ; clear display's line, reuse it
- mov dx,comand.cmprmp ; display the asciiz prompt
- call fprtasz
- prser3: mov bx,0ffffh ; returned keyword value
- mov sp,comand.cmostp ; set new sp to old one
- jmp dword ptr comand.cmrprs ; jump to just before the prompt call
- PRSERR ENDP
-
- ; Restore prompt material to that of the master prompt. This removes settings
- ; of local PROMPT calls so we can reprompt at the main Kermit level.
- RPROMPT proc near
- push ax
- mov ax,mcmprmp ; address of prompt string
- or ax,ax ; any address given yet?
- jz rprompt1 ; z = none, not inited yet
- mov comand.cmprmp,ax ; set current address ptr
- mov ax,word ptr mcmrprs ; offset of reparse address
- mov word ptr comand.cmrprs,ax
- mov ax,word ptr mcmrprs+2 ; segment of reparse address
- mov word ptr comand.cmrprs+2,ax
- mov ax,mcmostp ; stack ptr at reparse time
- mov comand.cmostp,ax
- rprompt1:pop ax
- ret
- RPROMPT endp
-
-
-
- ; write \v(ARGC) contents to ds:di
- wrtargc proc near
- xor ax,ax
- cmp taklev,0 ; in a Take/Macro?
- je wrtarg1 ; e = no
- mov bx,takadr ; current Take structure
- mov ax,[bx].takargc ; get ARGC
- wrtarg1:call fdec2di ; write as ascii
- mov word ptr [di],0020h ; space and null terminator
- inc di
- ret
- wrtargc endp
-
- ; write \v(COUNT) text to ds:di
- wrtcnt proc near
- xor ax,ax
- cmp taklev,0 ; in a Take/Macro?
- je wrtcnt1 ; e = no
- mov bx,takadr ; current Take structure
- mov ax,[bx].takctr ; get COUNT
- wrtcnt1:call fdec2di ; write as ascii
- mov word ptr [di],0020h ; space and null terminator
- inc di
- ret
- wrtcnt endp
-
- ; write \v(DATE) text to ds:di
- wrtdate proc near
- push cx
- push dx
- mov ah,getdate ; DOS date (cx= yyyy, dh= mm, dl= dd)
- int dos
- xor ah,ah
- cmp tdfmt,0 ; USA standard mm/dd/yyyy?
- jne wrtdat1 ; ne = no
- xor ah,ah
- mov al,dh ; month
- call wrtdat5 ; output
- mov byte ptr [di],'/' ; separate
- inc di
- xor ah,ah
- mov al,dl ; day
- call wrtdat5
- mov byte ptr [di],'/'
- inc di
- mov ax,cx
- jmp short wrtdat3
-
- wrtdat1:cmp tdfmt,1 ; European standard dd/mm/yyyy?
- jne wrtdat2 ; ne = no
- xor ah,ah
- mov al,dl ; day
- call wrtdat5
- mov byte ptr [di],'/'
- inc di
- xor ah,ah
- mov al,dh ; month
- call wrtdat5
- mov byte ptr [di],'/'
- inc di
- mov ax,cx
- jmp short wrtdat3
-
- wrtdat2:mov ax,cx ; Japan yyyy:mm:dd, year
- call wrtdat5
- mov byte ptr [di],':'
- inc di
- xor ah,ah
- mov al,dh ; month
- call wrtdat5
- mov byte ptr [di],':'
- inc di
- xor ah,ah
- mov al,dl ; day
- wrtdat3:call wrtdat5
- mov word ptr [di],0020h ; space and null terminator
- inc di
- pop dx
- pop cx
- ret
- ret
-
- wrtdat5:cmp ax,10 ; leading tens digit present?
- jae wrtdat6 ; ae = yes
- mov byte ptr [di],'0' ; insert leading 0
- inc di
- wrtdat6:call fdec2di ; write decimal asciiz to buffer
- ret
-
- wrtdate endp
-
- ; write \v(ERRORLEVEL) text to ds:di
- wrterr proc near
- mov al,errlev ; current Errorlevel
- xor ah,ah
- call fdec2di ; write as ascii
- mov word ptr [di],0020h ; space and null terminator
- inc di
- ret
- wrterr endp
-
- ; write \v(KEYBOARD) text to ds:di
- wrtkbd proc near
- mov ax,keyboard ; 88 or 101 keyboard keys
- call fdec2di ; write as ascii
- mov word ptr [di],0020h ; space and null terminator
- inc di
- ret
- wrtkbd endp
-
- ; write \v(NDATE) text to ds:di
- ; where NDATE is YYYYMMDD
- wrtndate proc near
- mov ah,getdate ; DOS date (cx= yyyy, dh= mm, dl= dd)
- int dos
- push dx ; save dx
- mov ax,cx ; year
- call fdec2di ; convert it
- pop dx ; get mm:dd
- push dx
- mov al,dh ; months are next
- xor ah,ah
- cmp al,10 ; less than 10?
- jae wrtndat1 ; ae = no
- mov byte ptr [di],'0' ; leading 0
- inc di
- wrtndat1:call fdec2di
- pop dx
- mov al,dl ; get days
- xor ah,ah
- cmp al,10 ; less than 10?
- jae wrtndat2 ; ae = no
- mov byte ptr [di],'0' ; leading 0
- inc di
- wrtndat2:call fdec2di
- mov word ptr [di],0020h ; space and null terminator
- inc di
- ret
- wrtndate endp
-
- ; write \v(DIRECTORY) text to ds:di
- wrtdir proc near
- push si
- mov ah,gcurdsk ; get current disk
- int dos
- add al,'A' ; make al = 0 == 'A'
- mov [di],al
- mov word ptr [di+1],'\:'
- mov si,di ; work buffer
- add si,3 ; end with a colon and backslash
- mov ah,gcd ; get current directory
- xor dl,dl ; use current drive
- int dos ; get ds:si = asciiz path (no drive)
- mov dx,di
- call fstrlen
- add di,cx
- cmp cx,3 ; directory added?
- je wrtdir1 ; e = no
- mov byte ptr [di],'\' ; add slash terminator so filenames
- inc di ; can be appended easily
- wrtdir1:mov word ptr [di],0020h ; space and null terminator
- inc di
- pop si
- ret
- wrtdir endp
-
- fwrtdir proc far
- call wrtdir
- ret
- fwrtdir endp
-
- ; write \v(PLATFORM) text to ds:di
- wrtplat proc near
- push si
- mov si,offset machnam ; machine name in sys dep file
- cld
- wrtplat1:lodsb ; get a char
- cmp al,'$' ; terminator?
- je wrtplat2 ; e = yes
- mov [di],al ; store char
- inc di
- jmp short wrtplat1 ; keep going
- wrtplat2:mov word ptr [di],0020h ; space and null terminator
- inc di
- mov temp,di ; place for additional text
- pop si
- ret
- wrtplat endp
-
- ; write \v(PORT) text to ds:di
- wrtport proc near
- push bx
- push si
- mov al,flags.comflg ; get coms port indicator
- mov bx,offset comptab ; table of comms ports
- mov cl,[bx] ; number of entries
- xor ch,ch
- inc bx
- wrtpor3:mov dx,[bx] ; length of this entry
- mov si,bx
- add si,2 ; points to entry text string
- add si,dx ; point to qualifier
- cmp [si],al ; our port?
- je wrtpor4 ; e = yes
- add bx,[bx] ; add text length
- add bx,4 ; plus count and qualifier
- loop wrtpor3 ; next entry
- jmp short wrtpor5 ; no match, curious
- wrtpor4:mov si,bx ; point at entry
- add si,2 ; point at string
- mov cx,[bx] ; length of string
- push es
- mov ax,ds
- mov es,ax
- cld
- rep movsb ; copy to DS:DI
- pop es
- wrtpor5:mov word ptr [di],0020h ; space and null terminator
- inc di
- pop si
- pop bx
- ret
- wrtport endp
-
- ; write \v(PROGRAM) text to ds:si
- wrtprog proc near
- push si
- mov si,offset progm ; source string
- cld
- wrtprg1:lodsb
- cmp al,'$' ; terminator?
- je wrtprg2 ; e = yes
- mov [di],al ; store the char
- inc di
- jmp short wrtprg1
- wrtprg2:mov word ptr [di],0020h ; space and null terminator
- inc di
- mov temp,di ; place for additional text
- pop si
- ret
- wrtprog endp
-
- ; write \v(STATUS) text to ds:di
- wrtstat proc near
- mov ax,kstatus ; Kermit status word
- call fdec2di
- mov word ptr [di],0020h ; space and null terminator
- inc di
- mov temp,di ; place for additional text
- ret
- wrtstat endp
-
- ; write \v(SYSTEM) text to ds:di
- wrtsystem proc near
- push si
- mov si,offset system ; system string "MS-DOS", dollar sign
- cld
- jmp wrtplat1 ; use some common code
- wrtsystem endp
-
- ; write \v(TIME) text to ds:di
- wrttime proc near
- mov ah,gettim ; DOS tod (ch=hh, cl=mm, dh=ss, dl=.s)
- int dos
- push dx ; save dx
- xor ah,ah
- mov al,ch ; Hours
- cmp al,10 ; leading digit?
- jae wrttim1 ; ae = yes
- mov byte ptr [di],'0' ; make our own
- inc di
- wrttim1:push cx
- call fdec2di ; write decimal asciiz to buffer
- pop cx
- mov byte ptr [di],':'
- inc di
- xor ah,ah
- mov al,cl ; Minutes
- cmp al,10 ; leading digit?
- jae wrttim2 ; ae = yes
- mov byte ptr [di],'0' ; make our own
- inc di
- wrttim2:call fdec2di ; write decimal asciiz to buffer
- mov byte ptr [di],':'
- inc di
- pop dx
- xor ah,ah
- mov al,dh ; Seconds
- cmp al,10 ; leading digit?
- jae wrttim3 ; ae = yes
- mov byte ptr [di],'0' ; make our own
- inc di
- wrttim3:call fdec2di ; write decimal asciiz to buffer
- mov word ptr [di],0020h ; space and null terminator
- inc di
- mov temp,di ; place for additional text
- ret
- wrttime endp
-
- ; write \v(Version) text to ds:di
- wrtver proc near
- mov si,offset verident ; MS Kermit version string in mssker
- cld
- wrtver1:lodsb
- mov [di],al
- inc di
- cmp al,'$' ; end of string?
- jne wrtver1 ; ne = no, continue copying
- dec di
- mov word ptr [di],0020h ; space and null terminator
- inc di
- mov temp,di ; place for additional text
- ret
- wrtver endp
-
- ; write \v(TERMINAL) text to ds:di
- wrtterm proc near
- mov ax,flags.vtflg ; current terminal type
- mov bx,offset termtb ; terminal type table msx...
- mov cl,[bx] ; number of entries in our table
- xor ch,ch
- inc bx ; point to the data
- wrtter1:mov si,[bx] ; length of keyword
- cmp ax,[bx+si+2] ; value fields match?
- je wrtter2 ; e = yes
- add bx,si ; add word length
- add bx,4 ; skip count and value fields
- loop wrtter1 ; keep searching
- jmp short wrtter4 ; no match, use just a space
- wrtter2:mov cx,[bx] ; get length of counted string
- mov si,bx
- add si,2 ; look at text
- cld
- wrtter3:lodsb
- mov [di],al ; from ds:si to ds:di
- inc di
- loop wrtter3
- wrtter4:mov word ptr [di],0020h ; space and null terminator
- inc di
- mov temp,di ; place for additional text
- ret
- wrtterm endp
-
- code1 ends
-
- code segment
- assume cs:code
-
- ; Set master prompt level. Enter with DX = offset of prompt string
- MPROMPT proc near
- mov mcmprmp,dx ; offset of prompt string
- pop ax ; get the return address
- mov word ptr mcmrprs,ax ; offset to go to on reparse
- mov mcmostp,sp ; stack pointer at reparse time
- push ax ; put it on the stack again
- mov ax,cs ; our current code segment
- mov word ptr mcmrprs+2,ax ; segment of reparse address
- jmp short prompt ; now set the active prompt material
- MPROMPT endp
-
- ; This routine prints the prompt and specifies the reparse address.
- ; Enter with pointer to prompt string in dx.
- PROMPT PROC NEAR
- mov comand.cmprmp,dx ; save the prompt
- pop ax ; get the return address
- mov word ptr comand.cmrprs,ax ; offset to go to on reparse
- mov comand.cmostp,sp ; save for later restoration
- push ax ; put it on the stack again
- mov ax,cs ; our current code segment
- mov word ptr comand.cmrprs+2,ax ; segment of reparse address
- mov ax,offset cmdbuf
- mov cmwptr,ax ; reset buffer read/write pointers
- mov cmrptr,ax
- xor al,al
- mov comand.cmper,al ; allow substitutions
- mov cmsflg,0ffh ; remove leading spaces
- cmp flags.takflg,al ; look at Take flag, zero?
- jne promp1 ; ne=supposed to echo, skip this check
- cmp taklev,al ; inside a take file?
- je promp1 ; no, keep going
- ret ; yes, return
- promp1: mov ah,prstr
- mov dx,offset crlf
- int dos
- mov dx,comand.cmprmp ; prompt pointer
- call prtasz ; show asciiz prompt string
- clc
- ret
- PROMPT ENDP
-
- ISDEV PROC NEAR ; Set carry if STDIN is non-disk
- push ax
- push bx
- push dx
- xor bx,bx ; handle 0 is stdin
- xor al,al ; get device info
- mov ah,ioctl
- int dos
- rcl dl,1 ; put ISDEV bit into the carry bit
- pop dx ; carry is set if device
- pop bx
- pop ax
- ret ; carry set if device
- ISDEV ENDP
-
- ISEOF PROC NEAR ; Set carry if STDIN is at EOF
- push ax ; but only if stdin is a non-device
- push bx
- push dx
- xor bx,bx ; handle 0 is stdin
- xor al,al ; get device info
- mov ah,ioctl
- int dos
- mov ah,ioctl
- mov al,6 ; get handle input status, set al
- test dl,80h ; bit set if handle is for a device
- jnz iseof1 ; nz = device, always ready (al != 0)
- int dos
- iseof1: or al,al ; EOF?
- pop dx
- pop bx
- pop ax
- jnz iseof2 ; nz = no
- stc ; set carry for eof
- ret
- iseof2: clc ; clear carry for not-eof
- ret
- ISEOF ENDP
-
- ; Convert ascii characters in al and ah to lowercase.
- ; All registers are preserved except AX, of course.
-
- TOLOWR PROC NEAR
- cmp ah,'A' ; less that cap A?
- jl tolow1 ; l = yes. leave untouched
- cmp ah,'Z'+1 ; more than cap Z?
- jns tolow1 ; ns = yes
- or ah,20H ; convert to lowercase
- tolow1: cmp al,'A' ; less that cap A?
- jl tolow2 ; l = yes. leave untouched
- cmp al,'Z'+1 ; more than cap Z?
- jns tolow2 ; ns = yes
- or al,20H ; convert to lowercase
- tolow2: ret
- TOLOWR endp
- code ends
-
- code1 segment
- assume cs:code1
-
- ; Parse control sequences and device control strings.
- ; Expect CSI, Escape [, or DCS lead-in characters to have been read.
- ; Puts numerical Parameters in array param (16 bits, count is nparam) and
- ; a single letter Parameter in lparam, (Parameters are all ASCII column 3)
- ; Intermediate characters in array inter (count is ninter), (ASCII column 2)
- ; Final character in AL (ASCII columns 4-7).
- ; Invoke by setting state to offset atparse, set pardone to offset of
- ; procedure to jump to after reading Final char (0 means do just ret)
- ; and optionally setting parfail to address to jump to if parsing failure.
- ; When the Final char has been accepted this routine jumps to label held in
- ; pardone for final action. Before the Final char has been read successful
- ; operations return carry clear.
- ; Failure exits are carry set, and an optional jump through parfail (if
- ; non-zero) or a return.
-
- atparse proc near
- mov bx,parstate ; get parsing state
- or bx,bx ; have any state?
- jnz atpars1 ; nz = have a state
- call atpclr ; do initialization
- mov bx,parstate ; get initial state
- atpars1:call bx ; execute it
- jc atpfail ; c = failure
- cmp parstate,offset atpdone ; parsed final char?
- je atpdone ; e = yes
- ret ; no, wait for another char
-
- ; successful conclusion, final char is in AL
- atpdone:mov parstate,0 ; reset parsing state
- cmp pardone,0 ; separate return address defined?
- jne atpdon1 ; ne = yes
- clc
- ret ; else just return
- atpdon1:clc
- jmp pardone ; jmp to supplied action routine
-
- atpfail:mov parstate,0 ; failed, reset parser to normal state
- cmp parfail,0 ; jump address specified?
- je atpfail1 ; e = no
- jmp parfail ; yes, exit this way
- atpfail1:stc
- ret
- ; parsing workers
- atparm: cmp ninter,0 ; Parameter, started intermediate yet?
- jne atinter ; ne = yes, no more parameters
- cmp al,';' ; argument separator?
- jne atparm3 ; ne = no
- mov ax,nparam ; number of Parameters
- inc ax ; say a new one
- cmp ax,maxparam ; too many?
- jb atparm2 ; b = no, continue
- stc ; set carry to say failed
- ret ; too many, ignore remainder
- atparm2:mov nparam,ax ; say doing another Parameter
- clc
- ret
-
- atparm3:mov ah,al ; copy char
- and ah,not 0fh ; ignore low nibble
- cmp ah,30h ; column 3, row 0? (30h='0')
- jne atparm6 ; ne = no, check Intermediate/Final
- cmp al,'9' ; digit?
- ja atparm5 ; a = no, check letter Parameters
- sub al,'0' ; ascii to binary
- mov bx,nparam ; current parameter number
- shl bx,1 ; convert to word index
- mov cx,param[bx] ; current parameter value
- shl cx,1 ; multiply by 10. 2 * cl
- push bx
- mov bx,cx ; save 2 * cl
- shl cx,1 ; 4 * cl
- shl cx,1 ; 8 * cl
- add cx,bx ; 10 * cl
- pop bx
- add cl,al ; add new digit
- adc ch,0
- jnc atparm4 ; nc = no carry out (65K or below)
- mov cx,0ffffh ; set to max value
- atparm4:mov param[bx],cx ; current Parameter value
- clc
- ret
- ; check non-numeric Parameters
- atparm5:cmp al,'?' ; within column 3?
- ja atfinal ; a = no, check Final char
- mov lparam,al ; store non-numeric Parameter
- clc
- ret
-
- atparm6:cmp nparam,0 ; started a parameter yet?
- jne atparm7 ; ne = yes
- cmp param,0 ; got anything for param[0]?
- je atinter ; e = no
- atparm7:inc nparam ; yes, say finished with another
-
- atinter:mov parstate,offset atinter ; next state (intermediate)
- cmp al,';' ; argument separator?
- jne atinte1 ; ne = no
- cmp ninter,maxinter ; too many intermediates?
- jb atinte2 ; b = no, continue
- stc ; carry = failed
- ret ; too many, ignore remainder
- atinte1:test al,not 2fh ; column two = 20h - 2fh?
- jnz atfinal ; nz = not an Intermediate, try Final
- cmp ninter,maxinter ; too many intermediates?
- jb atinte1a ; b = no, continue
- stc ; carry = failed
- ret ; too many, ignore remainder
- atinte1a:mov bx,ninter ; current Intermediate slot number
- mov inter[bx],al ; current Intermediate value
- atinte2:inc ninter ; say doing another Intermediate
- clc
- ret
-
- atfinal:cmp al,40h ; Final character, range is 40h to 7fh
- jb atfina1 ; b = out of range
- cmp al,7fh
- ja atfina1 ; a = out of range
- mov parstate,offset atpdone ; next state is "done"
- clc ; success, final char is in AL
- ret
- atfina1:stc ; c = failed
- ret
- atparse endp
-
- ; Clear Parameter, Intermediate arrays in preparation for parsing
- atpclr proc near
- push ax
- push cx
- push di
- push es
- xor ax,ax ; get a null
- mov parstate,offset atparm ; init parser state
- mov lparam,al ; clear letter Parameter
- mov nparam,ax ; clear Parameter count
- mov cx,maxparam ; number of Parameter slots
- mov di,offset param ; Parameter slots
- push ds
- pop es ; use data segment for es:di below
- cld ; set direction forward
- rep stosw ; clear the slots
- mov ninter,ax ; clear Intermediate count
- mov cx,maxinter ; number of Intermediate slots
- mov di,offset inter ; Intermediate slots
- rep stosb ; clear the slots
- pop es
- pop di
- pop cx
- pop ax
- ret
- atpclr endp
-
- ; Dispatch table processor. Enter with BX pointing at table of {char count,
- ; address of action routines, characters}. Jump to matching routine or return.
- ; Enter with AL holding received Final char.
- atdispat proc near
- mov cl,[bx] ; get table length from first byte
- xor ch,ch
- mov di,bx ; main table
- add di,3 ; point di at first char in table
- push es
- push ds
- pop es ; use data segment for es:di below
- cld ; set direction forward
- repne scasb ; find matching character
- pop es
- je atdisp2 ; e = found a match, get action addr
- ret ; ignore escape sequence
- atdisp2:sub di,bx ; distance scanned in table
- sub di,4 ; skip count byte, address word, inc
- shl di,1 ; convert to word index
- inc bx ; point to address of action routines
- mov bx,[bx] ; get address of action table
- jmp word ptr [bx+di] ; dispatch to the routine
- atdispat endp
- code1 ends
- end
-